#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <list>
#include <stack>
#include <queue>
#include <algorithm>
#include <set>
#include <map>
#include <deque>
#include <unordered_set>
#include <unordered_map>
#include <forward_list>
#include "UtilityMacro.h"
#define TYPE_RAW bool,char16_t,char32_t,int8_t,int16_t,int32_t,int64_t,uint8_t,uint16_t,uint32_t,uint64_t,float,double,string,vector,list,stack,queue,priority_queue,deque,pair,set,map,multiset,multimap,\
unordered_set,unordered_multiset,unordered_map,unordered_multimap


#define TYPE_PREFIX DT_
#define _DATA_TYPE_PREFIX(x) DT_##x
#define DATA_TYPE_PREFIX(x) _DATA_TYPE_PREFIX(x)
#define DATA_TYPE_PREFIX_WITHCOMMA(x) DATA_TYPE_PREFIX(x)M_COMMA
#define M_PREFIX(x) DATA_TYPE_PREFIX_WITHCOMMA(x)

#define TYPE_DEC CUSTOM, POINTER, M_PREFIX(bool) M_PREFIX(int8_t) M_PREFIX(uint8_t) M_PREFIX(char16_t) M_PREFIX(char32_t) M_PREFIX(int16_t) M_PREFIX(int32_t) M_PREFIX(int64_t) \
M_PREFIX(uint16_t) M_PREFIX(uint32_t) M_PREFIX(uint64_t) M_PREFIX(float) M_PREFIX(double) M_PREFIX(string) M_PREFIX(vector) M_PREFIX(list) M_PREFIX(stack) M_PREFIX(queue) M_PREFIX(priority_queue) \
M_PREFIX(deque) M_PREFIX(pair) M_PREFIX(set) M_PREFIX(map) M_PREFIX(multiset) M_PREFIX(multimap) M_PREFIX(unordered_set) M_PREFIX(unordered_multiset) M_PREFIX(unordered_map) M_PREFIX(unordered_multimap)

enum DataType{
    TYPE_DEC
};

const std::vector<std::string>& getAllTypeString(){
    static std::vector<std::string> vec_rawtype;
    static bool bInit = false;
    using namespace std;
    if (!bInit){
        std::string rawTypes=STR(TYPE_DEC);
        size_t pos = 0;
        while (pos <rawTypes.size()){
            size_t tpos = rawTypes.find_first_of(',',pos);
            if (tpos < rawTypes.size()){
                vec_rawtype.push_back(string(rawTypes.begin()+pos,rawTypes.begin()+tpos));
                pos = tpos + 1;
            }
            else{
                vec_rawtype.push_back(string(rawTypes.begin()+pos,rawTypes.end()));
                pos = rawTypes.size();
            }
        }
        bInit = true;
    }
    return vec_rawtype;
}

const std::vector<std::string>& getAllEnumTypeString()
{
    using namespace std;
    static vector<string> vec_enumtype;
    static bool bInit = false;
    const auto& vec_rawtype = getAllTypeString();
    if (!bInit){
        vec_enumtype = vec_rawtype;
        string pre = STR(TYPE_PREFIX);
        for (auto& item:vec_enumtype){
            item.insert(item.begin(),pre.begin(),pre.end());
            printf("%s,",item.c_str());
        }
        printf("\n");
        std::string traits_str = "DECLARE_TYPE_TRAITS";
        for (size_t i = 2; i< vec_enumtype.size();++i){
            const std::string& r = vec_rawtype[i];
            const std::string& e = vec_enumtype[i];
            printf("%s(%s, %s);\n",traits_str.c_str(),r.c_str(),e.c_str());
        }
    }
    return vec_enumtype;
}

void macrohelper()
{
    size_t num = 256;
    std::string macrostr;
    for (size_t i = 0;i<0;++i){
        macrostr = "#define SERIALIZE_MEMBER";
        macrostr += std::to_string(i+1);
        macrostr += "(C";
        for (size_t j = 1; j <= i+1;++j){
            macrostr+=",a";
            macrostr+= std::to_string(j);
        }
        macrostr+=") ByteStream& operator<<(ByteStream& bs, const C& obj) {bs";
        for (size_t j = 1; j <= i+1;++j){
            macrostr+="<<obj.a";
            macrostr+= std::to_string(j);
        }
        macrostr+=";return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs";
        for (size_t j = 1; j <= i+1;++j){
            macrostr+=">>obj.a";
            macrostr+= std::to_string(j);
        }
        macrostr +=";return bs;}";
        std::cout<<macrostr<<std::endl;
    }
}


/****************************************begin data type traits*********************************************************/
template<class T> struct data_type_traits{ static const char value = DataType::CUSTOM;};
template<class T> struct data_type_traits<T*>{ static const char value = DataType::POINTER;};
template<class T> struct data_type_traits<T&>{ static const char value = data_type_traits<T>::value;};
template<class T> struct data_type_traits<T&&>{ static const char value = data_type_traits<T>::value;};
template<class T> struct data_type_traits<const T>{ static const char value = data_type_traits<T>::value;};
#define DECLARE_TYPE_TRAITS(TYPE, ETYPE) template<> struct data_type_traits<TYPE>{static const char value = DataType::ETYPE;};
#define DECLARE_STDTYPE_TRAITS(TYPE, ETYPE) template<> struct data_type_traits<std::TYPE>{static const char value = DataType::ETYPE;};
#define DECLARE_STLCONT_TYPE_TRAITS(CONTTYPE, ETYPE) template<class T, class Alloc> struct data_type_traits<std::CONTTYPE<T,Alloc>>{static const char value = DataType::ETYPE;};
#define DECLARE_THREE_TYPE_TRAITS(CONTTYPE, ETYPE) template<class T1, class T2,class T3> struct data_type_traits<std::CONTTYPE<T1,T2,T3>>{static const char value = DataType::ETYPE;};
#define DECLARE_FOUR_TYPE_TRAITS(CONTTYPE, ETYPE) template<class T1, class T2,class T3, class T4> struct data_type_traits<std::CONTTYPE<T1,T2,T3,T4>>{static const char value = DataType::ETYPE;};
#define DECLARE_FIVE_TYPE_TRAITS(CONTTYPE, ETYPE) template<class T1, class T2,class T3, class T4, class T5> struct data_type_traits<std::CONTTYPE<T1,T2,T3,T4,T5>>{static const char value = DataType::ETYPE;};

DECLARE_TYPE_TRAITS(bool, DATA_TYPE_PREFIX(bool));
DECLARE_TYPE_TRAITS(int8_t, DATA_TYPE_PREFIX(int8_t));
DECLARE_TYPE_TRAITS(uint8_t, DATA_TYPE_PREFIX(uint8_t));
DECLARE_TYPE_TRAITS(char16_t, DATA_TYPE_PREFIX(char16_t));
DECLARE_TYPE_TRAITS(char32_t, DATA_TYPE_PREFIX(char32_t));
DECLARE_TYPE_TRAITS(int16_t, DATA_TYPE_PREFIX(int16_t));
DECLARE_TYPE_TRAITS(int32_t, DATA_TYPE_PREFIX(int32_t));
DECLARE_TYPE_TRAITS(int64_t, DATA_TYPE_PREFIX(int64_t));
DECLARE_TYPE_TRAITS(uint16_t, DATA_TYPE_PREFIX(uint16_t));
DECLARE_TYPE_TRAITS(uint32_t, DATA_TYPE_PREFIX(uint32_t));
DECLARE_TYPE_TRAITS(uint64_t, DATA_TYPE_PREFIX(uint64_t));
DECLARE_TYPE_TRAITS(float, DATA_TYPE_PREFIX(float));
DECLARE_TYPE_TRAITS(double, DATA_TYPE_PREFIX(double));

DECLARE_STDTYPE_TRAITS(string, DATA_TYPE_PREFIX(string));

DECLARE_STLCONT_TYPE_TRAITS(vector, DATA_TYPE_PREFIX(vector));
DECLARE_STLCONT_TYPE_TRAITS(list, DATA_TYPE_PREFIX(list));
DECLARE_STLCONT_TYPE_TRAITS(stack, DATA_TYPE_PREFIX(stack));
DECLARE_STLCONT_TYPE_TRAITS(queue, DATA_TYPE_PREFIX(queue));
DECLARE_STLCONT_TYPE_TRAITS(deque, DATA_TYPE_PREFIX(deque));
DECLARE_STLCONT_TYPE_TRAITS(pair, DATA_TYPE_PREFIX(pair));

DECLARE_THREE_TYPE_TRAITS(set, DATA_TYPE_PREFIX(set));
DECLARE_THREE_TYPE_TRAITS(multiset, DATA_TYPE_PREFIX(multiset));
DECLARE_THREE_TYPE_TRAITS(priority_queue, DATA_TYPE_PREFIX(priority_queue));

DECLARE_FOUR_TYPE_TRAITS(map, DATA_TYPE_PREFIX(map));
DECLARE_FOUR_TYPE_TRAITS(multimap, DATA_TYPE_PREFIX(multimap));
DECLARE_FOUR_TYPE_TRAITS(unordered_set, DATA_TYPE_PREFIX(unordered_set));
DECLARE_FOUR_TYPE_TRAITS(unordered_multiset, DATA_TYPE_PREFIX(unordered_multiset));

DECLARE_FIVE_TYPE_TRAITS(unordered_map, DATA_TYPE_PREFIX(unordered_map));
DECLARE_FIVE_TYPE_TRAITS(unordered_multimap, DATA_TYPE_PREFIX(unordered_multimap));

template<class T> char data_type_traits_v = data_type_traits<T>::value;
/****************************************end data type traits*********************************************************/
/****************************************begin class ByteStream*********************************************************/
class ByteStream
{
    friend class Serializer;
    std::vector<char> m_data;
    size_t m_pos;
protected:
    void write(const char* src, size_t len)
    {
        size_t size = m_data.size();
        size_t cap = m_data.capacity();
        while (size+len > cap){
            if (cap == 0) cap = 1;
            m_data.reserve(cap * 2);
            cap = m_data.capacity();
        }
        m_data.resize(size + len);
        memcpy(&m_data[size],src,len);
    }
    bool read(char* dst, size_t len)
    {
        size_t size = m_data.size();
        if (len + m_pos > size) return false;
        memcpy(dst,&m_data[m_pos],len);
        m_pos += len;
        return true;
    }
    //read next 4 bytes as int32
    int32_t readInt32()
    {
        int n;
        bool b = this->read((char*)&n,sizeof(int32_t));
        return b?n:0;
    }
    //get next read char but not increase read pos
    char peek()const{
        return m_pos < m_data.size() ? m_data[m_pos] : 0xff;
    }
public:
    ByteStream():m_pos(0){}
    void ResetWrite(){m_data.clear();}
    void ResetRead(){m_pos = 0;}
    size_t BytesCount()const{return m_data.size();}
    friend std::ostream& operator<<(std::ostream& os, const ByteStream& bs)
    {
        os.write(&bs.m_data[0],bs.m_data.size()); return os;
    }
    friend std::istream& operator>>(std::istream& is, ByteStream& bs)
    {
        size_t s =(size_t)is.tellg();
        is.seekg(0,std::ios::end);
        size_t e = (size_t)is.tellg();
        size_t count = e-s;
        is.seekg(s,std::ios::beg);
        size_t size = bs.m_data.size();
        size_t cap = bs.m_data.capacity();
        bs.m_data.resize(count + size);
        is.read(&bs.m_data[size],count); return is;
    }
    template<class T>
    friend ByteStream& operator<<(ByteStream& bs, const T& val){
        bs.write((char*)&val,sizeof(T));
        return bs;
    }
    template<class T>
    friend ByteStream& operator>>(ByteStream& bs,T& val){
        bs.read((char*)&val,sizeof(T));
        return bs;
    }
    friend ByteStream& operator<<(ByteStream& bs, const std::string& val){
        size_t len = val.size();
        bs<<len;
        for (size_t i =0;i<len;++i)
            bs<<val[i];
        return bs;
    }
    friend ByteStream& operator>>(ByteStream& bs, std::string& val){
        size_t len;
        bs>>len;
        for (size_t i =0;i<len;++i){
            char c; 
            bs>>c;
            val.push_back(c);
        }
        return bs;
    }
    template<class T, class Allocator, template<class, class>  class STLContainer>
    friend ByteStream& operator<<(ByteStream& bs,const STLContainer<T, Allocator>& val)
    {
        size_t size = val.size();
        bs<<size;
        for (const auto& item: val) 
            bs<<item;
        return bs;
    }
    template<class T, class Allocator, template<class, class>  class STLContainer>
    friend ByteStream& operator>>(ByteStream& bs,STLContainer<T, Allocator>& val)
    {
        size_t size;
        bs>>size;
        for (size_t i =0;i<size;++i){
            T tval; 
            bs>>tval;
            val.push_back(tval);
        }
        return bs;
    }
    template<class T, class Allocator> //stack
    friend ByteStream& operator<<(ByteStream& bs,const std::stack<T, Allocator>& val)
    {
        size_t size = val.size();bs<<size;
        auto stk = val;
        while (!stk.empty()){
            bs<<stk.top();
            stk.pop();
        }
        return bs;
    }
    template<class T, class Allocator> //stack
    friend ByteStream& operator>>(ByteStream& bs, std::stack<T, Allocator>& val)
    {
        size_t size;bs>>size;
        std::stack<T, Allocator> stk;
        for (size_t i = 0;i < size; ++i){
            T tval; bs>>tval;
            stk.push(tval);
        }
        while (!stk.empty()){
            val.push(stk.top());
            stk.pop();
        }
        return bs;
    }
    template<class T, class Container> //queue
    friend ByteStream& operator<<(ByteStream& bs,const std::queue<T, Container>& val)
    {
        size_t size = val.size();bs<<size;
        auto q = val;
        while (!q.empty()){
            bs<<q.front();
            q.pop();
        }
        return bs;
    }
    template<class T, class Container> //queue
    friend ByteStream& operator>>(ByteStream& bs, std::queue<T, Container>& val)
    {
        size_t size;bs>>size;
        for (size_t i = 0;i < size; ++i){
            T tval; bs>>tval;
            val.push(tval);
        }
        return bs;
    }
    template<class T, class Container, class _Pr> //priority_queue
    friend ByteStream& operator<<(ByteStream& bs, const std::priority_queue<T, Container, _Pr>& val)
    {
        size_t size = val.size(); bs << size;
        auto q = val;
        while (!q.empty()) {
            bs << q.top();
            q.pop();
        }
        return bs;
    }
    template<class T, class Container, class _Pr> //priority_queue
    friend ByteStream& operator>>(ByteStream& bs, std::priority_queue<T, Container, _Pr>& val)
    {
        size_t size; bs >> size;
        for (size_t i = 0; i < size; ++i) {
            T tval; bs >> tval;
            val.push(tval);
        }
        return bs;
    }
    template<class T1, class T2> //pair
    friend ByteStream& operator<<(ByteStream& bs, const std::pair<T1, T2>& val)
    {
        bs << val.first << val.second;
        return bs;
    }
    template<class T1, class T2> //pair
    friend ByteStream& operator>>(ByteStream& bs, std::pair<T1, T2>& val)
    {
        bs >> val.first >> val.second;
        return bs;
    }
    template<class _Kty, class _Pr, class _Alloc, template<class,class,class> class SET>              //for set multiset
    friend ByteStream& operator<<(ByteStream& bs, const SET<_Kty,_Pr,_Alloc>& s) {
        size_t size = s.size();
        bs << size;
        for (const auto& item : s) {
            bs << item;
        }
        return bs;
    }
    template<class _Kty, class _Pr, class _Alloc, template<class, class, class> class SET>              //for set multiset
    friend ByteStream& operator>>(ByteStream& bs, SET<_Kty, _Pr, _Alloc>& s) {
        size_t size;
        bs >> size;
        using T = typename SET<_Kty, _Pr, _Alloc>::value_type;
        std::vector<T> vec;
        for (size_t i = 0; i < size; ++i) {
            T tmp;
            bs >> tmp;
            vec.push_back(tmp);
        }
        s.insert(vec.begin(), vec.end());
        return bs;
    }
    template<class _Kty, class _Ty, class _Pr, class _Alloc, template<class, class, class, class> class MAP>              //for map multimap unordered_set unordered_multiset
    friend ByteStream& operator<<(ByteStream& bs, const MAP<_Kty, _Ty, _Pr, _Alloc>& m) {
        size_t size = m.size();
        bs << size;
        for (const auto& item : m) {
            bs << item;
        }
        return bs;
    }
    template<class _Kty, class _Ty, class _Pr, class _Alloc, template<class, class, class, class> class MAP>              //for map multimap unordered_set unordered_multiset
    friend ByteStream& operator>>(ByteStream& bs, MAP<_Kty, _Ty, _Pr, _Alloc>& m) {
        size_t size;
        bs >> size;
        using T = typename MAP<_Kty, _Ty, _Pr, _Alloc>::value_type;
        std::vector<T> vec;
        for (size_t i = 0; i < size; ++i) {
            T tmp;
            bs >> tmp;
            vec.push_back(tmp);
        }
        m.insert(vec.begin(), vec.end());
        return bs;
    }
    template<class _Kty, class _Ty, class _Hasher, class _Keyeq, class _Alloc, template<class, class, class, class,class> class MULMAP>              //for unordered_map unordered_multimap
    friend ByteStream& operator<<(ByteStream& bs, const MULMAP<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& m) {
        size_t size = m.size();
        bs << size;
        for (const auto& item : m) {
            bs << item;
        }
        return bs;
    }
    template<class _Kty, class _Ty, class _Hasher, class _Keyeq, class _Alloc, template<class, class, class, class, class> class MULMAP>               //for unordered_set unordered_multiset
    friend ByteStream& operator>>(ByteStream& bs, MULMAP<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& m) {
        size_t size;
        bs >> size;
        using T = typename MULMAP<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>::value_type;
        std::vector<T> vec;
        for (size_t i = 0; i < size; ++i) {
            T tmp;
            bs >> tmp;
            vec.push_back(tmp);
        }
        m.insert(vec.begin(), vec.end());
        return bs;
    }
};

/****************************************end class ByteStream*********************************************************/
void writeToByteStream(ByteStream& bs){}
template<class T, class ...Args>
void writeToByteStream(ByteStream& bs, T&& val, Args&& ...args)
{
    bs<<val; writeToByteStream(bs, args...);
}
void readFromByteStream(ByteStream& bs){}
template<class T, class ...Args>
void readFromByteStream(ByteStream& bs, T&& val, Args&& ...args)
{
    bs>>val; readFromByteStream(bs, args...);
}

/****************************************begin class Serializer*********************************************************/
class Serializer
{
public:
    struct ErrorMsg
    {
        enum{
            Success,
            TypeMismatch,
            ByteLengthMismatch
        };
        std::string errMsg = "Success";
        std::string wantedType;
        std::string realType;
        char errCode = Success;
        size_t errPos;
    };
    ErrorMsg lastError;
protected:
    ByteStream m_bytes;
public:
    void Clear(){m_bytes.ResetRead();m_bytes.ResetWrite();}
    ByteStream& GetByteStream(){return m_bytes;}
    template<class T>
    bool Serialize(T&& val){
        char type = data_type_traits_v<T>;
        m_bytes.write(&type,sizeof(char));
        int32_t pos = (int32_t)m_bytes.m_data.size();
        m_bytes<<val;
        pos = (int32_t)m_bytes.m_data.size() - pos;
        m_bytes<<pos;
        return true;
    }
    template<class T>
    bool DeSerialize(T& val){
        static_assert(!std::is_const<T>::value, "Deserialized value should be non-const.");
        char type = data_type_traits_v<T>;
        char curType = m_bytes.peek();
        if (curType != type) {
            const auto& strType = getAllTypeString();
            lastError = {"Type mismatch",strType[type],strType[curType],ErrorMsg::TypeMismatch,m_bytes.m_pos};
            return false;
        }
        m_bytes.read(&curType,sizeof(char));
        int32_t pos = (int32_t)m_bytes.m_pos;
        m_bytes>>val;
        int32_t diffpos = (int32_t)m_bytes.m_pos - pos;
        int32_t len = m_bytes.readInt32();
        if (!(diffpos == len)){
            const auto& strType = getAllTypeString();
            lastError = { "Bytes length mismatch! Probably due to sender and reciever are not coincident",strType[type],strType[curType],ErrorMsg::ByteLengthMismatch,size_t(pos - 1) };
            return false;
        }
        return true;
    }
    /*recursive serialize and deserialize*/
    bool Serialize(){return true;}
    bool DeSerialize(){return true;}
    template<class T, class ...Args>
    bool Serialize(T&& val, Args&&... args)
    {
        bool b = this->Serialize<T>(val);
        return b&&this->Serialize(args...);
    }
    template<class T, class ...Args>
    bool DeSerialize(T& val, Args&... args)
    {
        static_assert(!std::is_const<T>::value, "Deserialized value should be non-const.");
        bool b = this->DeSerialize<T>(val);
        return b&&this->DeSerialize(args...);
    }
    /*Load from istream or char source*/
    void Load(std::istream& is){is>>m_bytes;}
    void Load(const char* src, size_t len){m_bytes.write(src,len);}
    /*Save into ostream or string*/
    void Save(std::ostream& os)const{os<<m_bytes;}
    void Save(std::string& dst)
    {
        size_t len = m_bytes.m_data.size();
        dst.append(&m_bytes.m_data[0],len);
    }
};
/****************************************end class Serializer*********************************************************/

#define FRIEND_BYTESTREAM(CLASS) friend ByteStream& operator<<(ByteStream&,const CLASS&);friend ByteStream& operator>>(ByteStream&,CLASS&);


#define CAT_MACRO(MNAME,X) MNAME##X
#define _CAT_MACRO(MNAME,X) CAT_MACRO(MNAME,X)

#define _SER_MEMBER(...) _CAT_MACRO(SERIALIZE_MEMBER, UTIL_COUNT_ARG(__VA_ARGS__))
#define SER_MEMBER(C, ...) _SER_MEMBER(__VA_ARGS__)(C, __VA_ARGS__)
#define SERIALIZE_MEMBER1(C,a1) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1;return bs;}
#define SERIALIZE_MEMBER2(C,a1,a2) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2;return bs;}
#define SERIALIZE_MEMBER3(C,a1,a2,a3) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3;return bs;}
#define SERIALIZE_MEMBER4(C,a1,a2,a3,a4) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4;return bs;}
#define SERIALIZE_MEMBER5(C,a1,a2,a3,a4,a5) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5;return bs;}
#define SERIALIZE_MEMBER6(C,a1,a2,a3,a4,a5,a6) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6;return bs;}
#define SERIALIZE_MEMBER7(C,a1,a2,a3,a4,a5,a6,a7) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7;return bs;}
#define SERIALIZE_MEMBER8(C,a1,a2,a3,a4,a5,a6,a7,a8) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8;return bs;}
#define SERIALIZE_MEMBER9(C,a1,a2,a3,a4,a5,a6,a7,a8,a9) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9;return bs;}
#define SERIALIZE_MEMBER10(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10;return bs;}
#define SERIALIZE_MEMBER11(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11;return bs;}
#define SERIALIZE_MEMBER12(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12;return bs;}
#define SERIALIZE_MEMBER13(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12<<obj.a13;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12>>obj.a13;return bs;}
#define SERIALIZE_MEMBER14(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12<<obj.a13<<obj.a14;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12>>obj.a13>>obj.a14;return bs;}
#define SERIALIZE_MEMBER15(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12<<obj.a13<<obj.a14<<obj.a15;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12>>obj.a13>>obj.a14>>obj.a15;return bs;}
#define SERIALIZE_MEMBER16(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12<<obj.a13<<obj.a14<<obj.a15<<obj.a16;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12>>obj.a13>>obj.a14>>obj.a15>>obj.a16;return bs;}
#define SERIALIZE_MEMBER17(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12<<obj.a13<<obj.a14<<obj.a15<<obj.a16<<obj.a17;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12>>obj.a13>>obj.a14>>obj.a15>>obj.a16>>obj.a17;return bs;}
#define SERIALIZE_MEMBER18(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12<<obj.a13<<obj.a14<<obj.a15<<obj.a16<<obj.a17<<obj.a18;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12>>obj.a13>>obj.a14>>obj.a15>>obj.a16>>obj.a17>>obj.a18;return bs;}
#define SERIALIZE_MEMBER19(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12<<obj.a13<<obj.a14<<obj.a15<<obj.a16<<obj.a17<<obj.a18<<obj.a19;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12>>obj.a13>>obj.a14>>obj.a15>>obj.a16>>obj.a17>>obj.a18>>obj.a19;return bs;}
#define SERIALIZE_MEMBER20(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12<<obj.a13<<obj.a14<<obj.a15<<obj.a16<<obj.a17<<obj.a18<<obj.a19<<obj.a20;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12>>obj.a13>>obj.a14>>obj.a15>>obj.a16>>obj.a17>>obj.a18>>obj.a19>>obj.a20;return bs;}
#define SERIALIZE_MEMBER21(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12<<obj.a13<<obj.a14<<obj.a15<<obj.a16<<obj.a17<<obj.a18<<obj.a19<<obj.a20<<obj.a21;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12>>obj.a13>>obj.a14>>obj.a15>>obj.a16>>obj.a17>>obj.a18>>obj.a19>>obj.a20>>obj.a21;return bs;}
#define SERIALIZE_MEMBER22(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12<<obj.a13<<obj.a14<<obj.a15<<obj.a16<<obj.a17<<obj.a18<<obj.a19<<obj.a20<<obj.a21<<obj.a22;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12>>obj.a13>>obj.a14>>obj.a15>>obj.a16>>obj.a17>>obj.a18>>obj.a19>>obj.a20>>obj.a21>>obj.a22;return bs;}
#define SERIALIZE_MEMBER23(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12<<obj.a13<<obj.a14<<obj.a15<<obj.a16<<obj.a17<<obj.a18<<obj.a19<<obj.a20<<obj.a21<<obj.a22<<obj.a23;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12>>obj.a13>>obj.a14>>obj.a15>>obj.a16>>obj.a17>>obj.a18>>obj.a19>>obj.a20>>obj.a21>>obj.a22>>obj.a23;return bs;}
#define SERIALIZE_MEMBER24(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12<<obj.a13<<obj.a14<<obj.a15<<obj.a16<<obj.a17<<obj.a18<<obj.a19<<obj.a20<<obj.a21<<obj.a22<<obj.a23<<obj.a24;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12>>obj.a13>>obj.a14>>obj.a15>>obj.a16>>obj.a17>>obj.a18>>obj.a19>>obj.a20>>obj.a21>>obj.a22>>obj.a23>>obj.a24;return bs;}
#define SERIALIZE_MEMBER25(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12<<obj.a13<<obj.a14<<obj.a15<<obj.a16<<obj.a17<<obj.a18<<obj.a19<<obj.a20<<obj.a21<<obj.a22<<obj.a23<<obj.a24<<obj.a25;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12>>obj.a13>>obj.a14>>obj.a15>>obj.a16>>obj.a17>>obj.a18>>obj.a19>>obj.a20>>obj.a21>>obj.a22>>obj.a23>>obj.a24>>obj.a25;return bs;}
#define SERIALIZE_MEMBER26(C,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26) ByteStream& operator<<(ByteStream& bs, const C& obj) {bs<<obj.a1<<obj.a2<<obj.a3<<obj.a4<<obj.a5<<obj.a6<<obj.a7<<obj.a8<<obj.a9<<obj.a10<<obj.a11<<obj.a12<<obj.a13<<obj.a14<<obj.a15<<obj.a16<<obj.a17<<obj.a18<<obj.a19<<obj.a20<<obj.a21<<obj.a22<<obj.a23<<obj.a24<<obj.a25<<obj.a26;return bs;} ByteStream& operator>>(ByteStream& bs, C& obj) {bs>>obj.a1>>obj.a2>>obj.a3>>obj.a4>>obj.a5>>obj.a6>>obj.a7>>obj.a8>>obj.a9>>obj.a10>>obj.a11>>obj.a12>>obj.a13>>obj.a14>>obj.a15>>obj.a16>>obj.a17>>obj.a18>>obj.a19>>obj.a20>>obj.a21>>obj.a22>>obj.a23>>obj.a24>>obj.a25>>obj.a26;return bs;}
#define SERIALIZE_MEMBER(CLASS,...) SER_MEMBER(CLASS, __VA_ARGS__)